package com.android.kotlincoroutinemvvmdemo.view

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.view.View
import com.android.kotlincoroutinemvvmdemo.R
import java.util.LinkedList
import kotlin.random.Random

class AirBubblesView @JvmOverloads constructor(
    context: Context,
    attributeSet: AttributeSet? = null
) : View(context, attributeSet) {

    init {
        setBackgroundColor(resources.getColor(R.color.color_ffcccccc))
    }

    private var mWidth = 0
    private var mHeight = 0

    private val mPaint by lazy {
        Paint().apply {
            isAntiAlias = true
            isDither = true
            style = Paint.Style.FILL
            color = context.resources.getColor(R.color.color_da8989)
        }
    }

    private val mRandom = Random(10)

    private val pointsList = LinkedList<AirBubblesPoint>()

    private var animationStart = false

    private val animation = ValueAnimator().apply {
        setTarget(this@AirBubblesView)
        setFloatValues(0F, 2F)
        duration = 1000
        repeatMode = ValueAnimator.REVERSE
        repeatCount = ValueAnimator.INFINITE
        addUpdateListener {
            if (pointsList.size < 63) {
                addAirPoint()
            }
            invalidate()
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)

        mWidth = when(MeasureSpec.getMode(widthMeasureSpec)) {
            MeasureSpec.EXACTLY -> {
                MeasureSpec.getSize(widthMeasureSpec)
            }
            else -> {
                context.resources.getDimension(R.dimen.dp_200).toInt()
            }
        } - paddingStart - paddingEnd

        mHeight = when(MeasureSpec.getMode(heightMeasureSpec)) {
            MeasureSpec.EXACTLY -> {
                MeasureSpec.getSize(heightMeasureSpec)
            }
            else -> {
                context.resources.getDimension(R.dimen.dp_200).toInt()
            }
        } - paddingTop - paddingBottom

        setMeasuredDimension(mWidth, mHeight)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)

        if (!animationStart) {
            animationStart = true
            animation.start()
        }

        pointsList.forEach {
            val cx = it.finallyX()
            val cy = it.finallyY()
            canvas?.drawCircle(cx, cy, it.finallyR(), mPaint)
        }
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        recycle()
    }

    private fun recycle() {
        animation.cancel()
        pointsList.forEach {
            it.recycle()
        }
        pointsList.clear()
    }

    private fun addAirPoint() {
        val airPoint = createAirPoint()
        airPoint.duration = (mRandom.nextInt(7) + 4) * 1000
        pointsList.add(airPoint)
        airPoint.startAnimation()
    }

    private fun createAirPoint() : AirBubblesPoint = AirBubblesPoint(mHeight).apply {
        cx = mRandom.nextInt(mWidth).toFloat()
        cr = mRandom.nextInt(40) + AirBubblesPoint.minR * 2F
        cy = mHeight.toFloat() + cr
        airBubblesListener = resetListener
    }

    private val resetListener = object : AirBubblesPoint.AirBubblesListener {
        override fun resetX(): Float = mRandom.nextInt(measuredWidth).toFloat()
        override fun resetR(): Float = mRandom.nextInt(40) + AirBubblesPoint.minR * 2F
        override fun resetY(): Float = measuredHeight.toFloat()
    }

    companion object {
        const val TAG = "AirBubblesView"
    }
}

class AirBubblesPoint(private val length: Int) {
    //动画进度（0->1）
    private var progress = 0F

    var cx = 0F
    var cy = 0F
    var cr = minR.toFloat()
    var duration = 0

    var airBubblesListener: AirBubblesListener? = null
        set(value) {
            field = value
            if (cx < 0) {
                resetXY()
            }
        }

    private val animator = ObjectAnimator.ofFloat(this, "value", 0F, 1F).apply {
        repeatMode = ValueAnimator.RESTART
        repeatCount = ValueAnimator.INFINITE
        addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationRepeat(animation: Animator) {
                super.onAnimationRepeat(animation)
                //单次动画执行完毕后，重设圆信息
                resetXY()
            }
        })
    }

    private fun setValue(value: Float) {
        progress = value
    }

    fun finallyY(): Float = length - progress * length - finallyR()

    fun finallyX(): Float = cx

    fun finallyR(): Float = progress * (cr - minR) + minR

    fun startAnimation() {
        animator.duration = duration.toLong()
        animator.start()
    }

    private fun resetXY() {
        airBubblesListener?.let {
            cx = it.resetX()
            cr = it.resetR()
            cy = it.resetY() + cr
        }
    }

    fun recycle() {
        animator.cancel()
        airBubblesListener = null
    }

    //信息更新数据监听器
    interface AirBubblesListener {
        fun resetX(): Float
        fun resetY(): Float
        fun resetR(): Float
    }

    companion object {
        const val minR = 5
    }
}